// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// Package cmdflag处理多个go工具通用的标志处理。
package cmdflag

import (
	"errors"
	"flag"
	"fmt"
	"strings"
)

// test等go命令的标志处理部分很大，会分散注意力。
// 我们不能使用标准标志包，因为我们的命令行中的一些标志是为我们提供的，一些是为我们正在运行的二进制文件提供的，还有一些是为两者提供的。

// ErrFlagTerminator表示可分辨标记“-”，这会导致
// flag包将所有后续参数视为非标志。
var ErrFlagTerminator = errors.New("flag terminator")

// FlagNotDefinedError表示一个类似于标志的参数，它与标志集中的任何注册标志都不对应。
type FlagNotDefinedError struct {
	RawArg   string // 原始参数，比如--foo或-foo=value 
	Name     string
	HasValue bool   // 这是-foo=value或--foo=value形式吗？
	Value    string // 仅当HasValue为true时提供。shu jian defg
}

func (e FlagNotDefinedError) Error() string {
	return fmt.Sprintf("flag provided but not defined: -%s", e.Name)
}

type NonFlagError struct {
	RawArg string
}

func (e NonFlagError) Error() string {
	return fmt.Sprintf("not a flag: %q", e.RawArg)
}

// 
// ParseOne始终返回非零标志或非零错误，
// 并且始终使用至少一个参数（即使是在出现错误时）。
// 
// 与（*flag.FlagSet）不同。Parse，ParseOne不会记录自己的错误。
func ParseOne(fs *flag.FlagSet, args []string) (f *flag.Flag, remainingArgs []string, err error) {
	// 此函数大致源自（*flag.FlagSet）。一个。

	raw, args := args[0], args[1:]
	arg := raw
	if strings.HasPrefix(arg, "--") {
		if arg == "--" {
			return nil, args, ErrFlagTerminator
		}
		arg = arg[1:] // 将两个负数减为一个
	}

	switch arg {
	case "-?", "-h", "-help":
		return nil, args, flag.ErrHelp
	}
	if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' || arg[1] == '=' {
		return nil, args, NonFlagError{RawArg: raw}
	}

	name := arg[1:]
	hasValue := false
	value := ""
	if i := strings.Index(name, "="); i >= 0 {
		value = name[i+1:]
		hasValue = true
		name = name[0:i]
	}

	f = fs.Lookup(name)
	if f == nil {
		return nil, args, FlagNotDefinedError{
			RawArg:   raw,
			Name:     name,
			HasValue: hasValue,
			Value:    value,
		}
	}

	// 使用fs。设置而不是f值。设置如下，以便后续调用
	// fs。Visit将正确访问已设置的标志。

	failf := func(format string, a ...any) (*flag.Flag, []string, error) {
		return f, args, fmt.Errorf(format, a...)
	}

	if fv, ok := f.Value.(boolFlag); ok && fv.IsBoolFlag() { // 特殊情况：不需要arg 
		if hasValue {
			if err := fs.Set(name, value); err != nil {
				return failf("invalid boolean value %q for -%s: %v", value, name, err)
			}
		} else {
			if err := fs.Set(name, "true"); err != nil {
				return failf("invalid boolean flag %s: %v", name, err)
			}
		}
	} else {
		// 它必须有一个值，这可能是下一个参数。
		if !hasValue && len(args) > 0 {
			// 值是下一个参数
			hasValue = true
			value, args = args[0], args[1:]
		}
		if !hasValue {
			return failf("flag needs an argument: -%s", name)
		}
		if err := fs.Set(name, value); err != nil {
			return failf("invalid value %q for flag -%s: %v", value, name, err)
		}
	}

	return f, args, nil
}

type boolFlag interface {
	IsBoolFlag() bool
}
